SPB Git forge

spb/countryatlas

Public
20commits 1branches 0releases
268.3 MBsize
maindefault branch
12 days agolast push
TypeScript 57% Python 38.6% JavaScript 3.6% CSS 0.6%
2.6 KB · 46 lines tsx
Raw Blame History
1import { ImageResponse } from 'next/og';2import { t } from '@/i18n';3import { safe } from '@/lib/api';4import { apiCompare } from '@/lib/api-compare';5import { displayValue } from '@/lib/format';6import { OG_INK2, OG_INK3, OG_RULE, OG_SIZE_H, OG_SIZE_W, OgFrame, OgWordmark } from '../../og-shared';78export const alt = 'Country ranking on CountryAtlas';9export const size = { width: OG_SIZE_W, height: OG_SIZE_H };10export const contentType = 'image/png';11export const revalidate = 3600;1213/** Social image for /rankings/[indicator]: title + the top 3 (flag, name, value). */14export default async function RankingOgImage({ params }: { params: Promise<{ indicator: string }> }) {15  const { indicator } = await params;16  const data = await safe(apiCompare.ranking(indicator, { limit: 3, sparkline: false }));17  const name = data?.indicator.short_name ?? data?.indicator.name ?? indicator.replace(/-/g, ' ');18  const year = data?.year_used ?? '';19  return new ImageResponse(20    (21      <OgFrame>22        <OgWordmark size={28} />23        <div style={{ display: 'flex', flexDirection: 'column', marginTop: 48 }}>24          <div style={{ fontSize: 22, color: OG_INK3, textTransform: 'uppercase', letterSpacing: 2, display: 'flex' }}>{t('rankings.title')}</div>25          <div style={{ fontSize: name.length > 28 ? 52 : 64, fontWeight: 600, letterSpacing: -1.5, lineHeight: 1.05, marginTop: 8, display: 'flex' }}>{t('ranking.heading', { name })}</div>26          {year ? <div style={{ marginTop: 10, fontSize: 26, color: OG_INK2, display: 'flex' }}>{`${String(year)}${data ? ` · ${data.n} countries` : ''}`}</div> : null}27        </div>28        <div style={{ display: 'flex', gap: 40, marginTop: 'auto', paddingTop: 22, borderTop: `1px solid ${OG_RULE}` }}>29          {(data?.rows ?? []).slice(0, 3).map((r) => (30            <div key={r.country.id} style={{ display: 'flex', alignItems: 'center', gap: 14 }}>31              <div style={{ fontSize: 26, color: OG_INK3, display: 'flex' }}>{String(r.rank)}</div>32              <div style={{ fontSize: 44, lineHeight: 1, display: 'flex' }}>{r.country.flag ?? ''}</div>33              <div style={{ display: 'flex', flexDirection: 'column' }}>34                <div style={{ fontSize: 20, color: OG_INK2, display: 'flex' }}>{r.country.name ?? r.country.id}</div>35                <div style={{ fontSize: 30, fontWeight: 600, display: 'flex' }}>{displayValue(r.value, data!.indicator, r.formatted)}</div>36              </div>37            </div>38          ))}39        </div>40        <div style={{ position: 'absolute', right: 64, bottom: 24, fontSize: 20, color: OG_INK3 }}>{t('og.site')}</div>41      </OgFrame>42    ),43    { ...size },44  );45}46